Skip to content

[libcu++] Fix __is_sequence definition for arguments framework#9271

Open
miscco wants to merge 3 commits into
NVIDIA:mainfrom
miscco:fix_argument_sequence_definition
Open

[libcu++] Fix __is_sequence definition for arguments framework#9271
miscco wants to merge 3 commits into
NVIDIA:mainfrom
miscco:fix_argument_sequence_definition

Conversation

@miscco
Copy link
Copy Markdown
Contributor

@miscco miscco commented Jun 5, 2026

The current is_sequence definition is thoroughly broken. An iterator is not a sequence and neither is a pointer.

The main problem here is that this precludes passing along iterators / pointers as values which is a reasonable use case.

It also completely deviates from any standard handling in C++.

Rather than reinventing the wheel in a bad way use standard terminology to determine what is a range and what not.

A user can always wrap iterators and pointers into views and spans, so there is not need for the current definition

@miscco miscco requested a review from a team as a code owner June 5, 2026 07:17
@miscco miscco requested a review from Jacobfaib June 5, 2026 07:17
@github-project-automation github-project-automation Bot moved this to Todo in CCCL Jun 5, 2026
@cccl-authenticator-app cccl-authenticator-app Bot moved this from Todo to In Review in CCCL Jun 5, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 5, 2026

Review Change Stack

Note: CodeRabbit is enabled on this repository as a convenience for maintainers
and contributors. Use your best judgment when considering its review comments and
suggestions — a suggested change may be inadequate, unnecessary, or safe to ignore.
Contributors are not expected to address every comment. Human reviews are what
ultimately matter for merging.

Overview

This PR replaces a broken sequence-detection trait used by the arguments framework. The previous element-type-based logic misclassified many types (e.g., treating tuple/complex-like types and some wrappers as sequences, and preventing iterators/pointers from being passed as single values). The new approach narrows what is considered a sequence to arrays, types meeting ranges::range, or types that provide random-access traversal. Tests were added/adjusted to lock in the intended behavior and avoid regressions.

Changes

Implementation (libcudacxx/include/cuda/__argument/argument.h)

  • Redesigned __is_sequence_v:
    • New definition: is_array_v<remove_cvref_t<_Tp>> || ranges::range<_Tp> || __has_random_access_traversal<_Tp>.
    • This replaces the old element-type-comparison logic that caused misclassification.
  • Removed helper variable templates: __is_single_value_v and __is_iterable_v (old element-type helpers).
  • Primary traits behavior changed:
    • The primary __traits_impl<_Tp>::is_single_value no longer depends on the removed helper; the primary template is effectively made single-value-friendly (tests show raw pointers/iterators are treated as single values in trait queries).
  • Validation logic:
    • __immediate::__validate_value remains focused on single-value detection for arithmetic element types.
    • __immediate_sequence::__validate_value:
      • If __has_random_access_traversal<_Arg>, validation uses the random-access path (dereferencing the iterator/pointer).
      • Else, when __is_sequence_v<_Arg> and the element type is arithmetic, the code iterates the range to validate elements.
    • __constant_sequence static_assert message updated to require a “range or an array”.

Tests

  • libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp
    • Expanded negative coverage: static_assert that cuda::std::complex, pair, tuple, optional, expected are not sequences.
    • Confirmed plain types and wrapper-like types (range_like, element_type_like, value_type_like) are not sequences.
    • Confirmed pointers and counting iterators are sequences only when they provide random-access traversal; bidirectional iterators are not sequences.
    • Kept C arrays, spans, and std::array classified as sequences.
    • Updated argument_traits expectations: e.g., cuda::__argument::__traits<int*>::is_single_value is asserted true (reflecting the traits primary-template change).
  • libcudacxx/test/libcudacxx/cuda/argument/dynamic_argument.pass.cpp and static_argument.pass.cpp
    • Replaced previous __is_single_value_v assertions with assertions using !__is_sequence_v for unwrapped/value_type checks where appropriate.
  • libcudacxx/test/libcudacxx/cuda/argument/usage_example.pass.cpp
    • One plain-span test block is currently disabled (#if 0) with a FIXME comment.

Rationale & Impact

  • Aligns sequence detection with standard range terminology while preserving practical handling of random-access iterators/pointers where CUB historically allowed them.
  • Prevents misclassifying tuple-like or scalar-like types (e.g., std::complex) as sequences.
  • Tests added/updated to prevent regressions and to codify the intended semantics.
  • Note: runtime validation for random-access iterator/pointer sequences still uses dereference-based checks (with a FIXME comment noting that size may be unknown); reviewers may wish to consider whether additional iterator-size/validation strategies or clearer documentation are desirable.

Notes for reviewers

  • The change intentionally narrows __is_sequence_v but also alters the primary traits behavior so that some pointer/iterator cases remain treated as single values in trait queries. Verify this trade-off matches CUB compatibility goals.
  • The PR discussion suggested alternatives (broader acceptance of iterators/pointers, eliminating extra validation, or different validation strategies). This change adopts a middle path: standard-like detection of ranges plus explicit support for random-access traversal where needed.

Walkthrough

suggestion: Reclassifies sequence detection: a sequence is now an array (after cv/ref removal), a ranges::range, or has random-access traversal; removes __is_single_value_v/__is_iterable_v; updates immediate-sequence validation, trait primary template, and tests to use __is_sequence_v (negated for single-value).

Changes

Argument type classification by ranges::range

Layer / File(s) Summary
Core implementation: sequence and traits reclassification
libcudacxx/include/cuda/__argument/argument.h
Adds iterator/ranges/array includes; redefines __is_sequence_v<_Tp> as `is_array_v<remove_cvref_t<_Tp>>
Test validation of classification changes
libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp, libcudacxx/test/libcudacxx/cuda/argument/dynamic_argument.pass.cpp, libcudacxx/test/libcudacxx/cuda/argument/static_argument.pass.cpp, libcudacxx/test/libcudacxx/cuda/argument/usage_example.pass.cpp
Adds cuda/std headers used by new assertions; updates __is_sequence_v static_asserts to mark wrapper and several cuda::std types as not sequences; preserves sequence behavior for arrays/spans and random-access pointers/iterators; replaces prior __is_single_value_v checks with !__is_sequence_v where applicable; disables one plain-span test block via #if 0 (FIXME).
  • Possibly related PRs:

    • NVIDIA/cccl#8875: Related changes to argument.h sequence/single-value trait logic.
  • Suggested labels: libcu++

  • Suggested reviewers:

    • Jacobfaib

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Infer (1.2.0)
libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp

libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp:11:10: fatal error: 'cuda/_argument' file not found
11 | #include <cuda/argument>
| ^~~~~~~~~~~~~~~~~~
1 error generated.
Error: the following clang command did not run successfully:
/opt/infer-linux-x86_64-v1.2.0/lib/infer/facebook-clang-plugins/clang/install/bin/clang-18
@/tmp/coderabbit-infer/ce73d17754bb3703ff6fbcc0cbbbf2a51849c3cd-07842b3345a172fc/tmp/clang_command_.tmp.2c6159.txt
++Contents of '/tmp/coderabbit-infer/ce73d17754bb3703ff6fbcc0cbbbf2a51849c3cd-07842b3345a172fc/tmp/clang_command
.tmp.2c6159.txt':
"-cc1" "-load"
"/opt/infer-linux-x86_64-v1.2.0/lib/infer/infer/bin/../../facebook-clang-plugins/libtooling/build/FacebookClangPlugin.dylib"
"-add-plugin" "BiniouASTExporter" "-plugin-arg-BiniouASTExporter" "-"
"-plugin-arg-BiniouASTExporter" "PREPEND_CURRENT_DIR=1"
"-plugin-arg-BiniouASTExporter" "MAX_STRING_SIZE=65535" "-cc1" "-triple"
"x86_64-unknown-li

... [truncated 1169 characters] ...

al-isystem" "/usr/local/include" "-internal-isystem"
"/usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include"
"-internal-externc-isystem" "/usr/include/x86_64-linux-gnu"
"-internal-externc-isystem" "/include" "-internal-externc-isystem"
"/usr/include" "-Wno-ignored-optimization-argument" "-Wno-everything"
"-fdeprecated-macro" "-ferror-limit" "19" "-fgnuc-version=4.2.1"
"-fskip-odr-check-in-gmf" "-fcxx-exceptions" "-fexceptions"
"-D__GCC_HAVE_DWARF2_CFI_ASM=1" "-o"
"/tmp/coderabbit-infer/07842b3345a172fc/file.o" "-x" "c++"
"libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp" "-O0"
"-fno-builtin" "-include"
"/opt/infer-linux-x86_64-v1.2.0/lib/infer/infer/bin/../lib/clang_wrappers/global_defines.h"
"-Wno-everything"

libcudacxx/test/libcudacxx/cuda/argument/usage_example.pass.cpp

libcudacxx/test/libcudacxx/cuda/argument/usage_example.pass.cpp:16:10: fatal error: 'cuda/_argument' file not found
16 | #include <cuda/_argument>
| ^~~~~~~~~~~~~~~~~~
1 error generated.
libcudacxx/test/libcudacxx/cuda/argument/usage_example.pass.cpp:168:3-175:3: ERROR translating statement 'CompoundStmt'
Aborting translation of method 'test' in file 'libcudacxx/test/libcudacxx/cuda/argument/usage_example.pass.cpp': "Assert_failure src/clang/cAst_utils.ml:249:53"
Uncaught Internal Error: "Assert_failure src/clang/cAst_utils.ml:249:53"
Error backtrace:
Raised at ClangFrontend__CAst_utils.get_decl_from_typ_ptr in file "src/clang/cAst_utils.ml", line 249, characters 53-65
Called from ClangFrontend__CTrans.CTrans_funct.get_destructor_decl_ref in file "src/clang/cTrans.ml", line 658, characters 12-59
Called from ClangFrontend__CTrans.CTrans_funct.destructor_calls.(fun) in file "src/clang/cTrans.ml", line 2048, characters 12-69
Called from Base__List.rev_filter_map.loop

... [truncated 2200 characters] ...

3
Called from ClangFrontend__CTrans.CTrans_funct.instruction in file "src/clang/cTrans.ml" (inlined), line 4765, characters 38-71
Called from ClangFrontend__CTrans.CTrans_funct.exec_with_node_creation in file "src/clang/cTrans.ml" (inlined), line 104, characters 20-38
Called from ClangFrontend__CTrans.CTrans_funct.get_clang_stmt_trans in file "src/clang/cTrans.ml" (inlined), line 5395, characters 4-69
Called from ClangFrontend__CTrans.CTrans_funct.get_custom_stmt_trans in file "src/clang/cTrans.ml", line 5401, characters 8-55
Called from ClangFrontend__CTrans.CTrans_funct.exec_trans_instrs.exec_trans_instrs_rev in file "src/clang/cTrans.ml" (inlined), line 5365, characters 28-54
Called from ClangFrontend__CTrans.CTrans_funct.exec_trans_instrs in file "src/clang/cTrans.ml" (inlined), line 5


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
libcudacxx/include/cuda/__argument/argument.h (1)

114-114: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

important: The static_assert error messages "must have a distinct element type" are now incorrect. The new __is_sequence_v checks whether a type is an array or satisfies ranges::range, not whether it has a distinct element type. Types like element_type_like<int> have a distinct element type but are not arrays or ranges, so they would fail this check for a different reason than the message suggests.

Update the messages to reflect the actual requirement, e.g., "must be an array or range type".

Proposed fix
-  static_assert(__is_sequence_v<value_type>, "constant sequence arguments must have a distinct element type");
+  static_assert(__is_sequence_v<value_type>, "constant sequence arguments must be an array or range type");

Apply similar changes to lines 304, 701, and 714.

Also applies to: 304-304, 701-701, 714-714


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6b49057a-ad0c-4843-8771-66b0fd1e7ae9

📥 Commits

Reviewing files that changed from the base of the PR and between 2b21bec and 171cb93.

📒 Files selected for processing (4)
  • libcudacxx/include/cuda/__argument/argument.h
  • libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp
  • libcudacxx/test/libcudacxx/cuda/argument/dynamic_argument.pass.cpp
  • libcudacxx/test/libcudacxx/cuda/argument/static_argument.pass.cpp

@miscco miscco force-pushed the fix_argument_sequence_definition branch 2 times, most recently from 90a8c02 to f13ff25 Compare June 5, 2026 07:36
@miscco
Copy link
Copy Markdown
Contributor Author

miscco commented Jun 5, 2026

I have added some more tests to make sure this does not regresses again. I believe we can agree that complex<float> is not a range

@github-actions

This comment has been minimized.

inline constexpr bool __is_iterable_v<_Tp,
::cuda::std::void_t<decltype(::cuda::std::declval<const _Tp&>().begin()),
decltype(::cuda::std::declval<const _Tp&>().end())>> = true;
::cuda::std::is_array_v<::cuda::std::remove_cvref_t<_Tp>> || ::cuda::std::ranges::range<_Tp>;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An array is a range though, no? Why do you need both conditionals?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately not: https://godbolt.org/z/Eadh18x74

@pciolkosz
Copy link
Copy Markdown
Contributor

I am not tied to the name of this trait, but at the end of the day when user passes something that has bounds we need to understand if its one value or multiple values. We have the _sequence wrappers for that, but I wanted to provide some validation in it, this trait was supposed to answer if the thing in the wrapper looks like multiple values and what is the element type, so we can assert the values are within bounds.

I highly doubt we can convince others CUB should stop accepting iterators and pointers, so I believe we need a broader definition than just range, but maybe we can also remove the extra validation, which would remove the need for this trait. But it is likely in that case a similar trait would need to live in CUB anyway, so I am not sure if it isn't just pushing the problem to a different place

@miscco
Copy link
Copy Markdown
Contributor Author

miscco commented Jun 8, 2026

I highly doubt we can convince others CUB should stop accepting iterators and pointers

We should be able to still allow pointers and iterators if that is intended, but then the check should probably be __has_random_access_traversal or similar

Also we need to then differentiate iteration over a range and iteration over an iterator. Currently the check in __validate_value only considered ranges and not iterators

The issue I have here is that a pointer / iterator does not communicate the size of the range. In a perfect world we would just pass transform_view rather than transform_iterator

Not a hill to die on definitely but I at least want to make sure that we do not consider tuple or complex as sequences

miscco added 2 commits June 8, 2026 14:25
The  current is_sequence definition is thoroughly broken. An iterator is not a sequence and neither is a pointer.

The main problem here is that this precludes passing along iterators / pointers as values which is a reasonable use case.

It also completely deviates from any standard handling in C++.

Rather than reinventing the wheel in a bad way use standard terminology to determine what is a range and what not.

A user can always wrap iterators and pointers into views and spans, so there is not need for the current definition
@miscco miscco force-pushed the fix_argument_sequence_definition branch from f13ff25 to c7f5b4b Compare June 8, 2026 12:46
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
libcudacxx/test/libcudacxx/cuda/argument/usage_example.pass.cpp (1)

85-94: ⚡ Quick win

important: Line 85 disables the plain-span scenario with #if 0, which drops coverage instead of asserting the intended rejection behavior. Replace this block with an explicit negative test (compile-fail/static assertion in the argument test suite) so the contract is enforced by CI rather than commented out.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a8f64be5-de33-471d-b9c3-6f0c1e6388d6

📥 Commits

Reviewing files that changed from the base of the PR and between c7f5b4b and ce73d17.

📒 Files selected for processing (3)
  • libcudacxx/include/cuda/__argument/argument.h
  • libcudacxx/test/libcudacxx/cuda/argument/argument_traits.pass.cpp
  • libcudacxx/test/libcudacxx/cuda/argument/usage_example.pass.cpp

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 8, 2026

😬 CI Workflow Results

🟥 Finished in 1h 04m: Pass: 99%/115 | Total: 21h 05m | Max: 33m 37s | Hits: 98%/343670

See results here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Review

Development

Successfully merging this pull request may close these issues.

3 participants